package no.uib.hplims.tools.validators;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import no.uib.hplims.Controller;
import no.uib.hplims.models.Rule;
import com.vaadin.data.Validator;

public class SequenceValidator implements Validator {

	private static final long serialVersionUID = 904281452281679418L;

	Controller controller = null;
	
	ArrayList<String> validSequences = null;
	HashMap<String, List<String>> invalidSequences = null;

	public SequenceValidator(Controller controller) {
		this.controller = controller;
	}

	boolean isValid = false;

	public void validate(Object value) throws InvalidValueException {
		isValid = false;
		
		validSequences = new ArrayList<String>();
		invalidSequences = new HashMap<String, List<String>>();

		String sequences = (String) value;
		// make sure string is all uppercase
		sequences = sequences.toUpperCase();
		List<String> seq = Arrays.asList(sequences.split("\n"));
		int line = 1;
		Iterator<String> seqIt = seq.iterator();
		while (seqIt.hasNext()) {
			String sequence = seqIt.next();
			sequence = sequence.trim();
			// Confirm that sequence contains only valid amino acids.
			if (containsInvalidAminoAcids(sequence)) {
				addToInvalidSequenceList(sequence, "Contains invalid amino acid(s).");
			}

			// Validate sequence against the active rules the user has chosen.
			ArrayList<Rule> activeRules = controller.getActiveRules();
			Iterator<Rule> it = activeRules.iterator();
			while (it.hasNext()) {
				Rule r = it.next();
				String result = r.validate(sequence, line);
				if (result != "OK") {
					addToInvalidSequenceList(sequence, result);
				}
			}
			if (!invalidSequences.containsKey(sequence)) {
				validSequences.add(sequence);
			}
			line++;
		}

		System.out.println("Invalid sequences: " + invalidSequences.size());
		if (invalidSequences.isEmpty()) {
			isValid = true;
		}
	}

	// The isValid() method returns simply a boolean value, so
	// it can not return an error message.
	public boolean isValid(Object value) {
		if (value == null || !(value instanceof String)) {
			return false;
		}
		validate(value);
		return isValid;
	}
	
	private void addToInvalidSequenceList(String sequence, String error) {
		if (!invalidSequences.containsKey(sequence)) {
			List<String> l = new ArrayList<String>();
			l.add(error);
			invalidSequences.put(sequence, l);
		} else {
			List<String> l = invalidSequences.get(sequence);
			l.add(error);
		}
	}

	private boolean containsInvalidAminoAcids(String sequence) {
		String validAminoAcids = "ARNDCQEGHILKMFPSTWYV";
		String seq = sequence.toUpperCase();
		for (int i = 0, n = seq.length(); i < n; i++) {
			String aa = seq.substring(i, i + 1);
			if (!validAminoAcids.contains(aa)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * @return the validSequences
	 */
	public ArrayList<String> getValidSequences() {
		if (validSequences == null) {
			validSequences = new ArrayList<String>();
		}
		return validSequences;
	}

	/**
	 * @return the invalidSequences
	 */
	public HashMap<String, List<String>> getInvalidSequences() {
		if (invalidSequences == null) {
			invalidSequences = new HashMap<String, List<String>>();
		}
		return invalidSequences;
	}
}
